import type { PiniaPluginContext, StateTree } from "pinia"

export interface Serializable {
  serialize: () => string

  deserialize: (value: string) => void
}

declare module "pinia" {
  export interface DefineStoreOptionsBase<S extends StateTree, Store> {
    persist?: Array<string>
  }
}

class PersistLocalStorage {
  static read(key: string): string | null {
    return localStorage.getItem(key)
  }

  static write(key: string, value: string | undefined) {
    if (!value) {
      return
    }
    localStorage.setItem(key, value)
  }
}

class PersistServer {
  static read(key: string): string | null {
    //可以从后台读取数据，目前没有实现，是之间调用了本地存储
    return PersistLocalStorage.read(key)
  }

  static write(key: string, value: string | undefined) {
    if (!value) {
      return
    }
    //可以从后台读取数据，目前没有实现，是之间调用了本地存储
    PersistLocalStorage.write(key, value)
  }
}

/**
 * 判断是否登录，目前并没有真正实现，后续可以根据自己需要来实现
 */
function isLogin() {
  return false
}

function read(key: string) {
  let stateStr: string | null
  if (isLogin()) {
    //已经登录则从后台取
    stateStr = PersistServer.read(key)
  } else {
    //未登录则从本地存储取
    stateStr = PersistLocalStorage.read(key)
  }
  return stateStr
}

function write(key: string, value: string) {
  if (isLogin()) {
    //登录状态就存在后台
    PersistServer.write(key, value)
  } else {
    //未登录就存在本地
    PersistLocalStorage.write(key, value)
  }
}

export function persist(context: PiniaPluginContext) {
  if (!context.options.persist) {
    return
  }
  context.store.$subscribe((state) => {
    if (!context.options.persist) {
      return
    }
    for (const key of context.options.persist) {
      const value = context.store.$state[key]
      if (value && "serialize" in value) {
        const stateStr = (value as Serializable).serialize()
        write(context.store.$id + "_" + key, stateStr)
      }
    }
  })
  for (const key of context.options.persist) {
    const stateStr = read(context.store.$id + "_" + key)
    if (!stateStr) {
      continue
    }
    const value = context.store.$state[key]
    if (value && "deserialize" in value) {
      (value as Serializable).deserialize(stateStr)
    }
  }
}
